// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
// import com.alibaba.druid.sql.ast.statement.SQLTableElement;
// import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;

#include "MySqlShowColumnOutpuVisitor.h"
#include "../../../SQLUtils.h"
#include "../../../ast/SQLExpr.h"
#include "../../../ast/statement/SQLColumnDefinition.h"
#include "../../../ast/statement/SQLTableElement.h"
#include "../ast/MySqlUnique.h"
#include "../ast/statement/MySqlCreateTableStatement.h"
#include "../../../../utils/instanceof.h"

MySqlShowColumnOutpuVisitor::MySqlShowColumnOutpuVisitor(std::stringstream * appender)
    : MySqlOutputVisitor(appender)
{
}

BOOL_ptr MySqlShowColumnOutpuVisitor::visit(MySqlCreateTableStatement_ptr x)
{
  SQLColumnDefinition_list_ptr  columns;
  string_list_ptr dataTypes;
  string_list_ptr defaultValues;

  int name_len = -1, dataType_len = -1, defaultVal_len = 7, extra_len = 5;
  for (SQLTableElement_ptr element : *x->getTableElementList())
  {
    if (instanceof <SQLTableElement, SQLColumnDefinition>(element))
    {
      SQLColumnDefinition_ptr column = std::dynamic_pointer_cast<SQLColumnDefinition>(element);
      columns->push_back(column);

      string_ptr name = SQLUtils::normalize(column->getName()->getSimpleName());
      if (name_len < name->length())
      {
        name_len = name->length();
      }

      string_ptr dataType = column->getDataType()->getName();
      if (column->getDataType()->getArguments()->size() > 0)
      {
        dataType->append("(");
        auto it_getArguments = column->getDataType()->getArguments()->begin();
        for (int i = 0; i < column->getDataType()->getArguments()->size(); i++)
        {
          if (i != 0)
          {
            dataType->append(",");
          }
          std::advance(it_getArguments, i);
          SQLExpr_ptr arg = *it_getArguments;
          dataType->append(arg->toString()->c_str());
        }
        dataType->append(")");
      }

      if (dataType_len < dataType->length())
      {
        dataType_len = dataType->length();
      }
      dataTypes->push_back((dataType));

      if (column->getDefaultExpr() == nullptr)
      {
        defaultValues->push_back(make_string_ptr(""));
      }
      else
      {
        string_ptr defaultVal = SQLUtils::toMySqlString(column->getDefaultExpr());
        if (defaultVal->length() > 2 &&
            defaultVal->at(0) == '\'' &&
            defaultVal->at(defaultVal->length() - 1) == '\'')
        {
          defaultVal = make_string_ptr(defaultVal->substr(1, defaultVal->length() - 1));
        }
        defaultValues->push_back((defaultVal));

        if (defaultVal_len < defaultVal->length())
        {
          defaultVal_len = defaultVal->length();
        }
      }

      if (column->isAutoIncrement())
      {
        string_ptr auto_increment = make_string_ptr("auto_increment");
        extra_len = auto_increment->length();
      }
      else if (column->getOnUpdate() != nullptr)
      {
        string_ptr CURRENT_TIMESTAMP = make_string_ptr("on update CURRENT_TIMESTAMP");
        extra_len = CURRENT_TIMESTAMP->length();
      }
    }
  }

  SQLASTOutputVisitor::print("+-");
  print('-', name_len);
  SQLASTOutputVisitor::print("-+-");
  print('-', dataType_len);
  SQLASTOutputVisitor::print("-+------+-----+-");
  print('-', defaultVal_len);
  SQLASTOutputVisitor::print("-+-");
  print('-', extra_len);
  SQLASTOutputVisitor::print("-+\n");

  SQLASTOutputVisitor::print("| ");
  print(make_string_ptr("Field"), name_len, ' ');
  SQLASTOutputVisitor::print(" | ");
  print(make_string_ptr("Type"), dataType_len, ' ');
  SQLASTOutputVisitor::print(" | Null | Key | ");
  print(make_string_ptr("Default"), defaultVal_len, ' ');
  SQLASTOutputVisitor::print(" | ");
  print(make_string_ptr("Extra"), extra_len, ' ');
  SQLASTOutputVisitor::print(" |\n");

  SQLASTOutputVisitor::print("+-");
  print('-', name_len);
  SQLASTOutputVisitor::print("-+-");
  print('-', dataType_len);
  SQLASTOutputVisitor::print("-+------+-----+-");
  print('-', defaultVal_len);
  SQLASTOutputVisitor::print("-+-");
  print('-', extra_len);
  SQLASTOutputVisitor::print("-+\n");

  auto it_columns = columns->begin();
  auto it_dataTypes = dataTypes->begin();
  auto it_defaultValues = defaultValues->begin();
  for (int i = 0; i < columns->size(); i++)
  {
    std::advance(it_columns, i);
    SQLColumnDefinition_ptr column = *it_columns;
    string_ptr name = SQLUtils::normalize(column->getName()->getSimpleName());

    SQLASTOutputVisitor::print("| ");
    print(name, name_len, ' ');
    SQLASTOutputVisitor::print(" | ");

    print((*it_dataTypes), dataType_len, ' ');
    SQLASTOutputVisitor::print(" | ");

    if (column->containsNotNullConstaint())
    {
      SQLASTOutputVisitor::print("NO ");
    }
    else
    {
      SQLASTOutputVisitor::print("YES");
    }
    SQLASTOutputVisitor::print("  | ");

    MySqlUnique *unique;
    if (x->isPrimaryColumn(name))
    {
      SQLASTOutputVisitor::print("PRI");
    }
    else if (x->isUNI(name))
    {
      SQLASTOutputVisitor::print("UNI");
    }
    else if (x->isMUL(name))
    {
      SQLASTOutputVisitor::print("MUL");
    }
    else
    {
      SQLASTOutputVisitor::print("   ");
    }
    SQLASTOutputVisitor::print(" | ");

    std::advance(it_defaultValues, i);
    string_ptr defaultVal = (*it_defaultValues);
    if (defaultVal->empty())
    {
      print(make_string_ptr("NULL"), defaultVal_len, ' ');
    }
    else
    {
      print(defaultVal, defaultVal_len, ' ');
    }
    SQLASTOutputVisitor::print(" | ");

    if (column->isAutoIncrement())
    {
      print(make_string_ptr("auto_increment"), extra_len, ' ');
    }
    else if (column->getOnUpdate() != nullptr)
    {
      print(make_string_ptr("on update CURRENT_TIMESTAMP"), extra_len, ' ');
    }
    else
    {
      print(' ', extra_len);
    }
    SQLASTOutputVisitor::print(" |");
    SQLASTOutputVisitor::print("\n");
  }
  SQLASTOutputVisitor::print("+-");
  print('-', name_len);
  SQLASTOutputVisitor::print("-+-");
  print('-', dataType_len);
  SQLASTOutputVisitor::print("-+------+-----+-");
  print('-', defaultVal_len);
  SQLASTOutputVisitor::print("-+-");
  print('-', extra_len);
  SQLASTOutputVisitor::print("-+\n");

  return BOOL::FALSE;
}

void MySqlShowColumnOutpuVisitor::print(char ch, int count)
{
  for (int i = 0; i < count; ++i)
  {
    SQLASTOutputVisitor::print(ch);
  }
}

void MySqlShowColumnOutpuVisitor::print(string_ptr text, int columnSize, char ch)
{
  SQLASTOutputVisitor::print(text);
  print(' ', columnSize - text->length());
}
